package org.ysling.litemall.core.mvc.annotation.support;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.ysling.litemall.core.mvc.annotation.JsonBody;
import org.ysling.litemall.core.utils.JacksonUtil;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义请求参数注解
 * @author Ysling
 */
@Slf4j
public class JsonBodyArgumentResolver implements HandlerMethodArgumentResolver {


    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonBody.class);
    }

    @Override
    public Object resolveArgument(@Nonnull MethodParameter parameter,
                                  ModelAndViewContainer container,
                                  @Nonnull NativeWebRequest request,
                                  WebDataBinderFactory factory) {

        //获取自定义注解
        JsonBody jsonBody = parameter.getParameterAnnotation(JsonBody.class);
        if (jsonBody == null){
            return null;
        }
        //请求参数json
        String body = this.getJsonObject(request);
        //参数类型
        Class<?> classType = parameter.getParameterType();
        //获取注解参数名称
        String paramName = this.getParamName(parameter, jsonBody);
        //获取参数值
        Object paramValue = JacksonUtil.parseObject(body, paramName, classType);
        //判断参数是否必须
        if (paramValue == null && jsonBody.require()) {
            throw new RuntimeException("请求参数[" + paramName + "]不能为空。");
        }
        return paramValue;
    }


    /**
     * 获取参数名称
     */
    private String getParamName(MethodParameter parameter, JsonBody jsonBody) {
        String value = jsonBody.value();
        if (!StringUtils.hasText(value)) {
            value = parameter.getParameterName();
        }
        return value;
    }

    /**
     * 获取请求参数并转为json
     */
    private String getJsonObject(NativeWebRequest webRequest) {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        Assert.state(request != null, "No HttpServletRequest");
        StringBuilder value = new StringBuilder();
        //获取表单请求参数
        if (!StringUtils.hasText(value)){
            Map<String , String[]> params = request.getParameterMap();
            if (params.size() > 0){
                Map<Object , Object> tmp = new HashMap<>();
                for (Map.Entry<String , String[]> param : params.entrySet()) {
                    if(param.getValue().length == 1){
                        tmp.put(param.getKey(), param.getValue()[0]);
                    }else{
                        tmp.put(param.getKey(), param.getValue());
                    }
                }
                value.append(JacksonUtil.toJson(tmp));
            }
        }
        //获取请求体中参数
        if (!StringUtils.hasText(value)){
            try {
                //获取json请求，非json请求会抛出一次
                BufferedReader reader = request.getReader();
                char[] buf = new char[1024];
                int rd;
                while ((rd = reader.read(buf)) != -1) {
                    value.append(buf, 0, rd);
                }
                reader.close();
            }catch (Exception e){
                return "";
            }
        }
        return value.toString();
    }

}
